package com.tongjie.hotelbooking.config;

import com.tongjie.hotelbooking.security.entrypoint.ResponseBodyEntryPoint;
import com.tongjie.hotelbooking.security.provider.UserAuthenticationProvider;
import com.tongjie.hotelbooking.security.service.JpaUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;

import javax.annotation.Resource;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final RequestMatcher PUBLIC_URLS = new OrRequestMatcher(
            new AntPathRequestMatcher("/"),
            new AntPathRequestMatcher("/**", HttpMethod.OPTIONS.name()),
            new AntPathRequestMatcher("/csrf"),
            new AntPathRequestMatcher("/public/**"),
            new AntPathRequestMatcher("/sms/**"),
            new AntPathRequestMatcher("/**/*swagger*/**"),
            new AntPathRequestMatcher("/v2/api-docs"),
            new AntPathRequestMatcher("/admin/login/login")
    );

    private static final RequestMatcher PROTECTED_URLS = new NegatedRequestMatcher(PUBLIC_URLS);

    @Resource
    private FindByIndexNameSessionRepository<Session> sessionRepository;

    @Override
    public void configure(final WebSecurity web) {
        web.ignoring().requestMatchers(PUBLIC_URLS);
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER).sessionFixation().none().and()
                .exceptionHandling()
                .defaultAuthenticationEntryPointFor(entryPoint(), PROTECTED_URLS).and()
                .rememberMe()
                .rememberMeServices(this.rememberMeServices()).and()
                .authorizeRequests()
                .requestMatchers(PROTECTED_URLS).authenticated().and()
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().and()
                .requestCache().disable()
                .logout().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .authenticationProvider(this.authenticationProvider());
    }

    @Bean
    public UserAuthenticationProvider authenticationProvider() {
        return new UserAuthenticationProvider();
    }

//    @Bean
//    public UserDetailsService userDetailsService() {
//        return new JpaUserDetailsService();
//    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public SpringSessionRememberMeServices rememberMeServices() {
        SpringSessionRememberMeServices rememberMeServices = new SpringSessionRememberMeServices();
        rememberMeServices.setAlwaysRemember(true);
        return new SpringSessionRememberMeServices();
    }

    @Bean
    AuthenticationEntryPoint entryPoint() {
        return new ResponseBodyEntryPoint();
    }

}
